package com.cw.jeeyt.core.impl;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.List;

import org.apache.commons.codec.Charsets;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.cw.jeeyt.common.utils.MavenUtil;
import com.cw.jeeyt.common.utils.StringUtils;
import com.cw.jeeyt.core.intf.GitCore;

import lombok.extern.slf4j.Slf4j;

/**
 * Git操作工具类
 */
@Slf4j
@Service
public class GitCoreImpl implements GitCore {

    final static Logger LOG = LoggerFactory.getLogger(GitCoreImpl.class);
    private static String LOCAL_REPO_PATH = "D:/chenw_project/git_compile/";
    private static String LOCAL_REPOGIT_CONFIG = "D:/chenw_project/git_compile/";
    private static String REMOTE_REPO_URI = "https://gitee.com/cw8086/jeeyt.git";
    private  static String INIT_LOCAL_CODE_DIR = "D:/workspace";
    private static String LOCAL_FILE_DIR = "D:/workspace";
    private static String BRANCH_NAME = "master";
    private static String GIT_USERNAME = "244239226@qq.com";
    private static String GIT_PASSWORD = "244239226@qq";

    public static void main(String[] args) {
        new GitCoreImpl().setupRepository("jeeyt","master");
        new GitCoreImpl().pull("jeeyt","master");
        new GitCoreImpl().newBranch("jeeyt","dev1.1");
        new GitCoreImpl().checkout("jeeyt","dev1.1");
        new GitCoreImpl().pull("jeeyt","dev1.1");
        new MavenUtil().maven("D:/chenw_project/git_compile/","jeeyt","dev1.1");
        //pull();
        //newBranch("dev");
    }

    /**
     * sql脚本文件同步到git仓库
     *
     * @param sqlType SQl类型
     * @param loginName 系统登录名
     * @param fileName 文件名
     * @param sqlConent 文件内容
     * @param comment 提交说明
     * @return
     */
    @Override
    public boolean writeFileToGit(String sqlType, String loginName, String sqlConent, String fileName, String comment) {

        pull("","");
        String dest = LOCAL_FILE_DIR + sqlType
            .toLowerCase();
        String path = LOCAL_REPO_PATH + "/" + dest;
        File f = new File(path);
        if (!f.exists()) {
            f.mkdirs();
        }
        dest = dest + "/" + fileName;
        path = path + "/" + fileName;
        comment = loginName + " option of " + comment;
        return createFile(sqlConent, path) == commitAndPush(dest, comment);
    }

    /**
     * 根据主干master新建分支并同步到远程仓库
     *
     * @param branchName 分支名
     * @throws GitAPIException
     */
    @Override
    public String newBranch(String projectCode,String branchName) {
        String newBranchIndex = "refs/heads/" + branchName;
        String gitPathURI = "";
        try {
            Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG + projectCode + "/.git"));
            UsernamePasswordCredentialsProvider provider = new UsernamePasswordCredentialsProvider(GIT_USERNAME,
                GIT_PASSWORD);
            //检查新建的分支是否已经存在，如果存在则将已存在的分支强制删除并新建一个分支
            List<Ref> refs = git.branchList()
                .call();
            for (Ref ref : refs) {
                if (ref.getName()
                    .equals(newBranchIndex)) {
                    log.info("Removing branch before");
                    git.branchDelete()
                        .setBranchNames(branchName)
                        .setForce(true)
                        .call();
                    break;
                }
            }
            //新建分支
            Ref ref = git.branchCreate()
                .setName(branchName)
                .call();
            //推送到远程
            git.push()
                .setCredentialsProvider(provider)
                .add(ref)
                .call();
            gitPathURI = REMOTE_REPO_URI + " " + "feature/" + branchName;
        } catch (GitAPIException | IOException e) {
            e.printStackTrace();
        }
        return gitPathURI;
    }

    /**
     * 添加文件
     *
     * @param fileName
     * @return
     */
    @Override
    public boolean addFile(String fileName) {

        boolean addFileFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG))
            // Git git2 = new Git(new FileRepository(localRepoGitConfig));
        ) {
            // File myFile = new
            // File(git.getRepository().getDirectory().getParent(),filePath);
            // if(!myFile.createNewFile()) {
            // throw new IOException("Could not create file " + myFile);
            // }
            // add file to git
            String filePath = LOCAL_FILE_DIR + fileName;
            git.add()
                .addFilepattern(INIT_LOCAL_CODE_DIR)
                .call();
            log.info("Added file " + filePath + " to repository at " + git.getRepository()
                .getDirectory());
        } catch (Exception e) {
            e.printStackTrace();
            addFileFlag = false;
        }
        return addFileFlag;
    }

    /**
     * 提交代码到本地仓库
     *
     * @param comment 文件位置(相对仓库位置:a/b/file)
     * @param comment 提交git内容描述
     * @return
     */
    @Override
    public boolean commitFile(String comment) {

        boolean commitFileFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG))) {
            // 提交代码到本地仓库
            git.commit()
                .setMessage(comment)
                .call();
            LOG.info("Committed to repository at " + git.getRepository()
                .getDirectory());
        } catch (Exception e) {
            e.printStackTrace();
            commitFileFlag = false;
            LOG.error("commitFile error! \n" + e.getMessage());
        }
        return commitFileFlag;
    }
    @Override
    public boolean push() {

        boolean pushFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG));) {
            // 提交代码到本地仓库
            git.push()
                .call();
            LOG.info("push " + git.getRepository() + File.separator + git.getRepository()
                .getBranch());
        } catch (Exception e) {
            e.printStackTrace();
            pushFlag = false;
            LOG.error("push error! \n" + e.getMessage());
        }
        return pushFlag;
    }

    /**
     * 提交并推送代码至远程服务器
     *
     * @param filePath 提交文件路径(相对路径)
     * @param desc 提交描述
     * @return
     */
    @Override
    public boolean commitAndPush(String filePath, String desc) {

        boolean commitAndPushFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG))) {
            // //创建用户文件的过程
            // File myfile = new File(filePath);
            // myfile.createNewFile();
            UsernamePasswordCredentialsProvider provider = new UsernamePasswordCredentialsProvider(GIT_USERNAME,
                GIT_PASSWORD);
            git.add()
                .addFilepattern(filePath)
                .call();
            // 提交
            git.commit()
                .setMessage(desc)
                .call();
            // 推送到远程
            if (StringUtils.isBlank(GIT_USERNAME) || StringUtils.isBlank(GIT_PASSWORD)) {
                git.push()
                    .setCredentialsProvider(provider)
                    .call();
            } else {
                git.push()
                    .call();
            }
            LOG.info("Commit And Push file " + filePath + " to repository at " + git.getRepository()
                .getDirectory());
        } catch (Exception e) {
            e.printStackTrace();
            commitAndPushFlag = false;
            LOG.error("Commit And Push error! \n" + e.getMessage());
        }
        return commitAndPushFlag;

    }

    /**
     * 拉取远程代码
     *
     * @return 远程分支名
     */
    @Override
    public boolean pull(String projectCode,String remoteBranchName) {

        boolean pullFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG + projectCode))) {
            UsernamePasswordCredentialsProvider provider = new UsernamePasswordCredentialsProvider(GIT_USERNAME,
                GIT_PASSWORD);
            git.pull()
                .setRemoteBranchName(remoteBranchName)
                .setCredentialsProvider(provider)
                .call();
        } catch (Exception e) {
            e.printStackTrace();
            pullFlag = false;
        }
        return pullFlag;
    }

    /**
     * 检出项目
     *
     * @return
     */
    @Override
    public boolean checkout(String projectCode,String branchName) {

        boolean checkoutFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG + projectCode + "/.git"))) {
            git.checkout()
                .setName("refs/heads/" + branchName)
                .setForce(true)
                .call();
        } catch (Exception e) {
            e.printStackTrace();
            checkoutFlag = false;
        }
        return checkoutFlag;
    }

    /**
     * 从远程获取最新版本到本地 不会自动合并 merge
     *
     * @return
     */
    @Override
    public boolean fetch() {

        boolean fetchFlag = true;
        try (Git git = Git.open(new File(LOCAL_REPOGIT_CONFIG));) {
            git.fetch()
                .setCheckFetchedObjects(true)
                .call();
        } catch (Exception e) {
            e.printStackTrace();
            fetchFlag = false;
        }
        return fetchFlag;
    }

    /**
     * 拉取指定分支到本地
     *
     * @param projectIds
     * @param branchName
     * @return
     */
    @Override
    public boolean cloneGitProjectToLocal(String projectIds, String branchName, String cloneUrl) {
        if (StringUtils.isEmpty("projectIds")) {
            return false;
        }
        boolean resultFlag = false;
        String[] projectIdList = projectIds.split(",");

        String fileDir = INIT_LOCAL_CODE_DIR + "/" + branchName;
        // 检查目标文件夹是否存在
        File file = new File(fileDir);
        if (file.exists()) {
            deleteFolder(file);
        }
        Git git;
        try {
            git = Git.open(new File(LOCAL_REPOGIT_CONFIG));
            git.cloneRepository()
                .setURI(cloneUrl)
                .setDirectory(file)
                .call();
            resultFlag = true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (GitAPIException e) {
            e.printStackTrace();
        }
        return resultFlag;
    }

    /**
     * 拉取新创建的分支到本地
     *
     * @param cloneURL
     * @return
     */
    @Override
    public boolean pullNewBranchToLocal(String cloneURL) {
        boolean resultFlag = false;
        String[] splitURL = cloneURL.split(" ");
        String branchName = splitURL[1];
        String fileDir = INIT_LOCAL_CODE_DIR + "/" + branchName;
        // 检查目标文件夹是否存在
        File file = new File(fileDir);
        if (file.exists()) {
            deleteFolder(file);
        }
        Git git;
        try {
            git = Git.open(new File(LOCAL_REPOGIT_CONFIG));
            git.cloneRepository()
                .setURI(cloneURL)
                .setDirectory(file)
                .call();
            resultFlag = true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (GitAPIException e) {
            e.printStackTrace();
        }
        return resultFlag;
    }
    @Override
    public void deleteFolder(File file) {
        if (file.isFile() || file.list().length == 0) {
            file.delete();
        } else {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
                deleteFolder(files[i]);
                files[i].delete();
            }
        }
    }

    /**
     * 生成文件写内容
     *
     * @param content 文件内容
     * @param filePath 文件名称
     */
    @Override
    public boolean createFile(String content, String filePath) {

        // 删除前一天临时目录
        // File af = new
        // File(filePath+File.separator+DateUtil.getAgoBackDate(-1));
        // if (af.exists()) {
        // deleteFolder(af);
        // }
        // //创建临时存储目录
        // File f = new
        // File(filePath+File.separator+DateUtil.getAgoBackDate(0));
        // if (!f.exists()) {
        // f.mkdirs();
        // }
        // if (!fileName.endsWith(".sql")) {
        // fileName+=".sql";
        // }
        boolean createFileFlag = true;
        File file = new File(filePath);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
                createFileFlag = false;
            }
        }
        try (BufferedWriter bw = new BufferedWriter(
            new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8));) {
            bw.write(content);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            createFileFlag = false;
        } catch (IOException e) {
            e.printStackTrace();
            createFileFlag = false;
        }
        return createFileFlag;
    }

    /**
     * 创建本地新仓库
     *
     * @param repoPath 仓库地址 D:/workspace/TestGitRepository
     * @return
     * @throws IOException
     */
    @Override
    public Repository createNewRepository(String repoPath) throws IOException {
        File localPath = new File(repoPath);
        // create the directory
        Repository repository = FileRepositoryBuilder.create(new File(localPath, ".git"));
        repository.create();
        return repository;
    }

    /**
     * 创建仓库，仅需要执行一次
     */
    @Override
    public boolean setupRepository(String projectPath,String baseBranch) {
        boolean setupRepositoryFlag = true;
        Git git = null;
        try {
            // 设置远程服务器上的用户名和密码
            UsernamePasswordCredentialsProvider provider = new UsernamePasswordCredentialsProvider(GIT_USERNAME,
                GIT_PASSWORD);
            if (StringUtils.isBlank(GIT_USERNAME) || StringUtils.isBlank(GIT_PASSWORD)) {
                // 设置远程URI
                // 设置clone下来的分支,默认master
                // 设置下载存放路径
                git = Git.cloneRepository()
                    .setURI(REMOTE_REPO_URI)
                    .setBranch(baseBranch)
                    .setDirectory(new File(LOCAL_REPO_PATH + projectPath))
                    .call();
            } else {
                // 设置远程URI
                // 设置clone下来的分支,默认master
                // 设置下载存放路径
                // 设置权限验证
                git = Git.cloneRepository()
                    .setURI(REMOTE_REPO_URI)
                    .setBranch("master")
                    .setDirectory(new File(LOCAL_REPO_PATH + projectPath))
                    .setCredentialsProvider(provider)
                    .call();
            }
        } catch (Exception e) {
            e.printStackTrace();
            setupRepositoryFlag = false;
        }
        return setupRepositoryFlag;
    }
}
